package com.mrzhou.data.aspect;

import com.mrzhou.core.exception.BusinessException;
import com.mrzhou.core.tool.utils.ClassUtil;
import com.mrzhou.data.annotation.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

@Aspect
@Slf4j
public class RedisLockAspect implements Ordered {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * Redission 分布式锁切面实现
     * @return
     */
    @Around("@annotation(com.mrzhou.data.annotation.RedisLock) || @within(com.mrzhou.data.annotation.RedisLock)")
    public Object redisLockAround(ProceedingJoinPoint point) throws Throwable {
        // 获取方法签名(通过此签名获取目标方法信息)
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取当前动态代理的对象
        Method method = signature.getMethod();
        RedisLock redisLock = ClassUtil.getAnnotation(method, RedisLock.class);
        RLock lock = redissonClient.getLock(redisLock.key());
        try {
            if (lock.tryLock(redisLock.waitTime(), redisLock.leaseTime(), redisLock.unit())) {
                // 成功获取锁执行方法
                return point.proceed();
            }
            throw new BusinessException("获取锁超时，请稍后重试");
        } catch (Throwable e) {
            log.error("系统异常： {}", e);
            throw e;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("释放锁成功 key:[{}]", redisLock.key());
            }
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
